import { Window } from './window'
import { Element } from './element'
import { EntityMap, EntityId } from './entity_map'
import { Renderer } from './renderer'
import { WebGLRenderer } from './webgl_renderer'
import { Scene } from './scene'

/**
 * 窗口无效器接口
 */
export interface WindowInvalidator {
  invalidate_view(entityId: EntityId, app: App): void
}

/**
 * 渲染器类型枚举
 */
export enum RendererType {
  DOM,
  WebGL
}

/**
 * 应用选项接口
 */
export interface AppOptions {
  rendererType?: RendererType;
}

/**
 * 效果类型
 */
export enum EffectType {
  Notify,
  Emit,
  RefreshWindows,
  NotifyGlobalObservers,
  Defer,
  EntityCreated
}

/**
 * 效果接口
 */
export interface Effect {
  type: EffectType
}

/**
 * 通知效果
 */
export interface NotifyEffect extends Effect {
  type: EffectType.Notify
  emitter: EntityId
}

/**
   * 应用类，管理窗口和元素树
   */
  export class App {
    private windows: Window[] = []
  private entityMap: EntityMap
  private rootElement: Element | null = null // 用于存储根元素引用
  private rendererType: RendererType;
  private domRenderer: Renderer;
  private webglRenderer: WebGLRenderer | null = null;
  private mountPoint: HTMLElement | null = null
  private windowInvalidatorsByEntity: Map<EntityId, Map<number, WindowInvalidator>> = new Map()
  private trackedEntities: Map<number, Set<EntityId>> = new Map()
  private pendingNotifications: Set<EntityId> = new Set()
  private pendingEffects: Array<Effect> = []
  
  // VSync和渲染循环相关属性
  private animationFrameId: number | null = null
  private needsRender: boolean = false
  private lastInputTimestamp: number = 0
  private active: boolean = true
  private lastRenderedScene: Scene | null = null
  private lastRenderedContainer: HTMLElement | null = null
  
  /**
   * 获取根元素
   */
  getRootElement(): Element | null {
    return this.rootElement
  }

  constructor(options: AppOptions = {}) {
    this.entityMap = new EntityMap()
    this.rendererType = options.rendererType || RendererType.DOM
    this.domRenderer = new Renderer()
    this.lastRenderedScene = null
    this.lastRenderedContainer = null
    
    // 如果选择WebGL渲染器，则创建WebGL渲染器实例
    if (this.rendererType === RendererType.WebGL) {
      this.webglRenderer = new WebGLRenderer()
    }
    
    // 注册到全局对象，以便组件访问
    if (typeof window !== 'undefined') {
      (window as any)['gpuiApp'] = this
      
      // 监听窗口事件以更新状态
      // window.addEventListener('focus', () => {
      //   this.active = true
      //   this.requestRender()
      // })
      
      window.addEventListener('blur', () => {
        this.active = false
      })
      
      // 监听鼠标和键盘事件以更新最后输入时间戳
      window.addEventListener('mousemove', () => {
        this.lastInputTimestamp = Date.now()
      })
      
      window.addEventListener('keydown', () => {
        this.lastInputTimestamp = Date.now()
      })
    }
  }
  
  /**
   * 设置渲染器类型
   */
  setRendererType(type: RendererType): void {
    this.rendererType = type
    
    // 如果切换到WebGL渲染器但尚未创建，则创建WebGL渲染器实例
    if (type === RendererType.WebGL && !this.webglRenderer) {
      this.webglRenderer = new WebGLRenderer()
    } else if (type === RendererType.DOM) {
      // 切换回DOM渲染器
      this.webglRenderer = null
    }

    // 切换渲染器类型时需要重置上次渲染状态
    this.lastRenderedScene = null
    this.lastRenderedContainer = null
    
    // 触发重新渲染
    this.render()
  }
  
  /**
   * 获取当前渲染器类型
   */
  getRendererType(): RendererType {
    return this.rendererType
  }

  /**
   * 将应用挂载到DOM元素
   */
  mount(element: HTMLElement): void {
    this.mountPoint = element
    this.createDefaultWindow()
    this.render()
  }

  /**
   * 创建默认窗口
   */
  private createDefaultWindow(): void {
    const window = new Window(this)
    // 如果已经有根元素，立即设置给新创建的窗口
    if (this.rootElement) {
      window.setRootElement(this.rootElement)
    }
    this.windows.push(window)
  }

  /**
   * 设置根元素
   */
  setRootElement(element: Element): void {
    this.rootElement = element
    // 将根元素设置给所有窗口
    for (const window of this.windows) {
      window.setRootElement(element)
    }

    this.render()
  }

  /**
   * 渲染整个应用
   */
  render(): void {
    console.log('App.render: 开始渲染应用')
    if (!this.mountPoint) {
      console.log('App.render: 没有找到挂载点')
      return
    }
    
    // 清空挂载点
    this.mountPoint.innerHTML = ''

    // 遍历所有窗口，让它们先绘制到Scene
    for (const window of this.windows) {
      window.drawRoots()
      const scene = window.getScene()
      
      // 判断是需要完整渲染还是增量渲染
      if (!this.lastRenderedScene || !this.lastRenderedContainer || this.isFullRenderNeeded(scene)) {
        // 完整渲染
        this.performFullRender(scene)
      } else {
        // 增量渲染
        this.performIncrementalRender(scene)
      }
      
      // 保存当前渲染状态
      this.lastRenderedScene = scene
    }
    
    // 渲染完成后重置需要渲染的标志
    this.needsRender = false
    console.log('App.render: 渲染完成')
  }
  
  /**
   * 执行完整渲染
   */
  private performFullRender(scene: Scene): void {
    if (!this.mountPoint) return
    
    // 根据渲染器类型选择不同的渲染方法
    if (this.rendererType === RendererType.WebGL && this.webglRenderer) {
      // 使用WebGL渲染器
      const canvas = this.webglRenderer.renderScene(scene)
      this.mountPoint.appendChild(canvas)
      this.lastRenderedContainer = canvas as HTMLElement
    } else {
      // 使用DOM渲染器
      const container = this.domRenderer.renderScene(scene)
      this.mountPoint.appendChild(container)
      this.lastRenderedContainer = container as HTMLElement
    }
  }
  
  /**
   * 执行增量渲染
   */
  private performIncrementalRender(scene: Scene): void {
    if (!this.lastRenderedContainer) return
    
    // 根据渲染器类型调用相应的增量渲染方法
    if (this.rendererType === RendererType.WebGL && this.webglRenderer && 'updateScene' in this.webglRenderer) {
      // WebGL渲染器的增量渲染
      const webglRenderer = this.webglRenderer as any;
      const success = webglRenderer.updateScene(scene);
      // 如果增量渲染失败，回退到完整渲染
      if (!success && this.mountPoint) {
        this.performFullRender(scene);
      }
    } else if (this.rendererType === RendererType.DOM && 'updateScene' in this.domRenderer) {
      // DOM渲染器的增量渲染
      const domRenderer = this.domRenderer as any;
      domRenderer.updateScene(scene, this.lastRenderedContainer);
    }
  }
  
  /**
   * 检查是否需要完整渲染
   */
  private isFullRenderNeeded(_scene: Scene): boolean {
    // 可以根据场景的复杂度、变化的程度等因素来决定是否需要完整渲染
    // 这里我们简单判断：如果场景有大量更新，就使用完整渲染
    
    // 对于WebGL渲染器，我们总是需要清空画布重新绘制
    if (this.rendererType === RendererType.WebGL) {
      return false;
    }
    
    // 其他情况可以根据实际需求调整判断逻辑
    return false;
  }
  
  /**
   * 请求渲染，通过requestAnimationFrame调度下一次渲染
   */
  requestRender(): void {
    if (this.needsRender) {
      return
    }
    
    this.needsRender = true
    
    // 确保只有一个requestAnimationFrame在运行
    if (this.animationFrameId === null) {
      this.animationFrameId = requestAnimationFrame(() => this.handleAnimationFrame())
    }
  }
  
  /**
   * 处理requestAnimationFrame回调（相当于VSync信号）
   */
  private handleAnimationFrame(): void {
    this.animationFrameId = null
    
    // 检查是否需要渲染
    const shouldRender = this.needsRender || 
                       (this.active && (Date.now() - this.lastInputTimestamp < 1000))
    
    if (shouldRender) {
      this.render()
    }
    
    // 如果应用是活动的，并且最近有输入，则继续请求下一帧
    if (this.active && (Date.now() - this.lastInputTimestamp < 1000)) {
      this.requestRender()
    }
  }
  
  /**
   * 开始渲染循环
   */
  startRenderLoop(): void {
    this.requestRender()
  }
  
  /**
   * 停止渲染循环
   */
  stopRenderLoop(): void {
    if (this.animationFrameId !== null) {
      cancelAnimationFrame(this.animationFrameId)
      this.animationFrameId = null
    }
    this.needsRender = false
  }
  
  /**
   * 获取应用是否处于活动状态
   */
  isActive(): boolean {
    return this.active
  }
  
  /**
   * 设置应用活动状态
   */
  setActive(active: boolean): void {
    this.active = active
    if (active) {
      this.requestRender()
    } else {
      this.stopRenderLoop()
    }
  }

  /**
   * 获取实体映射
   */
  getEntityMap(): EntityMap {
    return this.entityMap
  }

  /**
   * 记录窗口访问的实体
   */
  recordEntitiesAccessed(
    windowId: number,
    invalidator: WindowInvalidator,
    entities: Set<EntityId>
  ): void {
    // 移除之前跟踪的实体
    const previousEntities = this.trackedEntities.get(windowId) || new Set()
    for (const entityId of previousEntities) {
      const windowInvalidators = this.windowInvalidatorsByEntity.get(entityId)
      if (windowInvalidators) {
        windowInvalidators.delete(windowId)
        if (windowInvalidators.size === 0) {
          this.windowInvalidatorsByEntity.delete(entityId)
        }
      }
    }

    // 跟踪新的实体
    const newTrackedEntities = new Set<EntityId>(entities)
    for (const entityId of entities) {
      if (!this.windowInvalidatorsByEntity.has(entityId)) {
        this.windowInvalidatorsByEntity.set(entityId, new Map())
      }
      this.windowInvalidatorsByEntity.get(entityId)!.set(windowId, invalidator)
    }

    this.trackedEntities.set(windowId, newTrackedEntities)
  }

  /**
   * 通知实体变更
   */
  notify(entityId: EntityId): void {
    const windowInvalidators = this.windowInvalidatorsByEntity.get(entityId)

    if (!windowInvalidators || windowInvalidators.size === 0) {
      // 如果没有窗口无效器，将通知添加到待处理队列
      if (!this.pendingNotifications.has(entityId)) {
        this.pendingNotifications.add(entityId)
        const notifyEffect: NotifyEffect = { type: EffectType.Notify, emitter: entityId }
        this.pendingEffects.push(notifyEffect)
      }
    } else {
      // 如果有窗口无效器，立即通知它们
      for (const invalidator of windowInvalidators.values()) {
        invalidator.invalidate_view(entityId, this)
      }
    }

    // 处理待处理的效果
    this.flushEffects()
  }

  /**
   * 处理待处理的效果
   */
  private flushEffects(): void {
    while (this.pendingEffects.length > 0) {
      const effect = this.pendingEffects.shift()
      if (!effect) break

      switch (effect.type) {
        case EffectType.Notify:
          const notifyEffect = effect as NotifyEffect
          this.applyNotifyEffect(notifyEffect.emitter)
          break
        // 其他效果类型的处理可以在这里添加
        case EffectType.RefreshWindows:
          this.applyRefreshEffect()
          break
        default:
          break
      }
    }
  }

  /**
   * 应用通知效果
   */
  private applyNotifyEffect(emitter: EntityId): void {
    this.pendingNotifications.delete(emitter)
    // 这里可以添加观察者通知逻辑
  }

  /**
   * 应用刷新效果
   */
  private applyRefreshEffect(): void {
    this.requestRender()
  }
}